# coding=utf-8
# 脱密：将文件中所有手机号的4~7位和身份证号的6~15位用 * 替换
#
# 附加要求
# 对指定文件夹中的所有文件进行批量处理
#
# 对 Excel 文档进行同样操作

# 思路1：使用正则识别出文件中所有的手机号和身份证号，然后再使用正则将手机号与身份证号修改为我们需要的格式

# 编程开始

# 设置编码


# 导入re模块
import re
# 导入os模块
import os
# 导入线程模块
import threading
# 导入excel文件读模块
import xlrd
# 导入excel文件写模块
import xlwt

# 11位数字的正则
num_reg_11 = r'\d{11}'
# 测试身份证号的正则
id_card_num_reg_18 = r'\d{18}|\d{17}[X|x]'
# 手机号的正则
phone_reg = r'((13[0-9])|(14[5|7])|(15([0-3]|[5-9]))|(18[0,5-9]))\d{8}'
# 18位身份证号的正则
id_card_reg = r'\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|[xX])'
# 当前文件所在目录
current_dir = os.path.dirname(__file__)
# 资源文件夹所在目录
source_dir = os.path.dirname(current_dir) + '/resource'
file_path = source_dir + '/1.txt'
new_file_path = source_dir + '/1_new.txt'


# 判断字符串s是否同时满足正则reg1，reg2
def contain_reg(s, reg1, reg2):
    pattern = re.compile(reg1)
    num_str = pattern.findall(s)
    if num_str:
        pattern = re.compile(reg2)
        match = pattern.match(str(num_str[0]))
        if match:
            return True
    else:
        return False


# 从字符串s中获取同时满足正则reg1和reg2的部分
def get_str_by_reg(s, reg1, reg2):
    # 匹配正则
    pattern = re.compile(reg1)
    num_str = pattern.findall(s)
    # 匹配成功，是18位数字
    if num_str:
        pattern = re.compile(reg2)
        match = pattern.match(str(num_str[0]))
        # 连续的18位数字是身份证号码
        if match:
            return match.group()


# 将给定数字中的从n到m位(包含n和m位)用指定的符号来代替
def replace_num_by_char(s, n, m, c):
    # 字符串的前n位
    str_prefix = s[0:n - 1]
    # 字符串m位后面的几位
    str_suffix = s[-(len(s) - m):]
    temp = (m - n + 1) * c
    return str_prefix + temp + str_suffix


# 获取脱密后的身份证号:将身份证号（18位号的身份证，15位的占时不考虑）的6~15位用 * 替换
def desensitization_id_card(id_card):
    return replace_num_by_char(id_card, 6, 15, "*")


# 获取脱敏后的电话号码：手机号的4~7位用*号表示
def desensitization_phone(phone):
    return replace_num_by_char(phone, 4, 7, "*")


# 将文件里的电话号码脱密
def handle_txt_for_desensitization(path):
    # 判断文件是否存在
    if os.path.exists(path):
        new_lines = []
        with open(path, 'r+', encoding='utf-8') as f:
            # 读取文件的内容
            lines = f.readlines()
            for line in lines:
                # 判断字符串是否包含电话号码
                if contain_reg(line, num_reg_11, phone_reg):
                    # 获取字符串中的电话号码的部分
                    phone = get_str_by_reg(line, num_reg_11, phone_reg)
                    # 获取脱密后的电话号码
                    phone_desensi = desensitization_phone(phone)
                    line = line.replace(phone, phone_desensi)

                if contain_reg(line, id_card_num_reg_18, id_card_reg):
                    # 获取字符串中身份证号码的部分
                    id_card = get_str_by_reg(line, id_card_num_reg_18, id_card_reg)
                    # 获取脱密后的身份证号
                    id_card_desensi = desensitization_id_card(id_card)
                    line = line.replace(id_card, id_card_desensi)
                else:
                    pass
                new_lines.append(line)
        # 打印内容，查看
        return new_lines
    else:
        print("指定路径的文件不存在" + path)
        return None


# 将指定的内容写入一个新的普通文件中
def write_to_txt_file(path, content):
    # 判断文件是否已经存在
    if os.path.exists(path):
        print("该文件已经存在，无法新建:" + path)
        return False
    else:
        with open(path, 'w', encoding='utf-8') as f:
            for s in content:
                f.write(s)
        print("文件写入完成:"+path)
        return True


# 处理txt类型的文件
def handle_file_of_txt(file, new_path):
    # 获取脱密后的文件内容
    new_content = handle_txt_for_desensitization(file)
    # 判断获取是否失败
    if new_content:
        write_to_txt_file(new_path, new_content)


# 处理文件
def handle_file(file, new_file):
    if not os.path.exists(file):
        return False

    # 判断文件类型
    file_type = file.split(".")[1]
    if file_type == 'txt':
        handle_file_of_txt(file, new_file)
    if file_type == 'xlsx':
        handle_file_of_excel(file, new_file)


# 1.2 ---------------多线程处理文件夹下面的文件

# 获取指定目录下的所有文件,包含子目录的文件
def get_all_file_from_dir(root_path):
    # os.walk() 函数实现遍历指定目录及所有子目录下的所有文件,返回一个三元组
    files = []
    for root, dir, file_list in os.walk(root_path):
        # print(root)   # 根目录
        # print(dir)    # 子目录，不是全路径名
        for file in file_list:
            full_path = os.path.join(root, file)  # 获取文件的全路径
            full_path = full_path.replace('\\\\', '/')  # 替换路径中的'\\'
            files.append(full_path)
    return files


def get_list_from_dir(path):
    lists = os.listdir(path)
    lists.sort(key=lambda fn: os.path.getmtime(path + "\\" + fn) if not os.path.isdir(path + "\\" + fn) else 0)
    last_file_name = lists[-1]
    file_dir = os.path.join(path, last_file_name)
    print(file_dir)


# get_list_from_dir(source_dir + "/resource")

# 从path路径中获取一个新的路径：例如 1.txt 会得到1_2.txt文件
def get_new_path(path):
    name = str(path).split(".")
    return name[0] + "_2." + name[1]


# 多线程处理文件
def hand_file_by_mutil_thread(root):
    files = get_all_file_from_dir(root)
    for i in files:
        t = threading.Thread(target=handle_file, args=(i, get_new_path(i),))
        t.start()


# 读取execl文件的内容:     path ：文件全路径 , i：要读取的sheet的索引值  ,allRead: 是否读取所有sheet的内容
def read_file_from_execl(path, i=None, allRead=False):
    if i == None:
        i = 0
    exists = os.path.exists(path)
    if exists:
        # 打开excel文件
        excel_file = xlrd.open_workbook(filename=path, encoding_override='utf-8')
        # 获取sheet,若有多个sheet，则需要指定读取目标sheet的索引
        sheet = excel_file.sheet_by_index(i)
        # 读取sheet的内容
        return read_content_from_sheet(sheet)
    else:
        print("该excel文件不存在：" + path)
        return None


# 写入指定的内容content到file,如果file不存在，就创建该文件.sheet是excel文件中展示的sheet的名称。grids是保存grid的数组
# grid包含 row: 行数  col:列数   data:单元格的内容
def write_file_of_excel(file, grids, sheet_name=None):
    # 设置默认的sheet名称
    if not sheet_name:
        sheet_name = '1'
        # 如果文件不存在，就创建
    if not os.path.exists(file):
        excel_file = xlwt.Workbook(encoding='utf-8', style_compression=0)
        sheet = excel_file.add_sheet(sheet_name)
        sheet = write_grid_to_sheet(grids, sheet)
        excel_file.save(file)
        print("excel文件内容写入完成:" + file)


# 将指定的单元格的内容写入sheet
def write_grid_to_sheet(grids, sheet):
    for grid in grids:
        row_num = grid['row']
        col_num = grid['col']
        data = grid['data']
        sheet.write(row_num, col_num, data)
    print("单元格内容写入sheet完成！")
    return sheet


# 从sheet中读取内容(以行为单位进行处理),返回一个grid数组,grid包含 row: 行数  col:列数   data:单元格的内容
def read_content_from_sheet(sheet):
    # 获取sheet的行数
    rows = sheet.nrows
    # 获取sheet的列数
    cols = sheet.ncols
    # 获取所有单元格内容
    if not sheet and not cols:
        return None
    else:
        grids = []
        for i in range(0, rows):
            for j in range(0, cols):
                data = str(sheet.cell(i, j).value.encode('utf-8'), encoding='utf-8')
                grid = {'row': i, 'col': j, 'data': data}
                grids.append(grid)
        return grids


# 处理excel文件
def handle_file_of_excel(file, new_file):
    grids = handle_excel_for_desensitization(file)
    if grids:
        write_file_of_excel(new_file, grids)


# 读取excel文件的内容，并且脱密手机号和身份证号,返回grids
def handle_excel_for_desensitization(file):
    # 读取excel文件的内容
    grids = read_file_from_execl(file)
    if not grids:
        print("读取excel文件内容失败:" + file)
        return None
    # 将grids的内容脱密
    for grid in grids:
        # 判断字符串是否包含电话号码
        data = grid['data']
        if contain_reg(data, num_reg_11, phone_reg):
            # 获取字符串中的电话号码的部分
            phone = get_str_by_reg(data, num_reg_11, phone_reg)
            # 获取脱密后的电话号码
            phone_desensi = desensitization_phone(phone)
            grid['data'] = data.replace(phone, phone_desensi)
        if contain_reg(data, id_card_num_reg_18, id_card_reg):
            # 获取字符串中身份证号码的部分
            id_card = get_str_by_reg(data, id_card_num_reg_18, id_card_reg)
            # 获取脱密后的身份证号
            id_card_desensi = desensitization_id_card(id_card)
            grid['data'] = data.replace(id_card, id_card_desensi)
    return grids


# 获取excel文件的内容
# excel_file = source_dir + '/excle_1.xlsx'
# new_excel_file = source_dir + '/excle_2.xlsx'
# grids = read_file_from_execl(excel_file)
# if grids:
#     write_file_of_excel(new_excel_file, grids)


# 获取目录下的所有文件
hand_file_by_mutil_thread(source_dir)


